import { getHttpInfo, getHttp } from "@/store";
import { createBlankForm, hasOwn } from "@/utils";
import qs from "qs";

export const REQUEST_GET = 'GET';
export const REQUEST_POST = 'POST';
export const REQUEST_JSONP = 'JSONP';
export const REQUEST_ROW = 'ROW';

/**
 * 整合请求地址
 * @returns {string}
 */
const makeUrl = (options, config) => {
    if (!options.url) {
        throw new Error('未指定请求地址');
    }

    let url = options.url;

    if (url.indexOf('/') != 0 && url.indexOf('http') != 0) {
        url = config.baseURL + url;
    }

    const prefix = url.indexOf('http') != 0 ? 'http://xxx.xxx' : '';
    const tempURL = new URL(prefix + url);

    for (const name in options.params) {
        if (hasOwn(options.params, name) && options.params[name] !== undefined) {
            tempURL.searchParams.append(name, options.params[name]);
        }
    }

    const getURL = () => tempURL.toString().slice(prefix.length);

    if (options.method == REQUEST_GET && config.onGetRequestCommonFields) {
        const commonParams = config.onGetRequestCommonFields(getURL(), config);

        if (typeof commonParams == 'object') {
            for (const name in commonParams) {
                if (hasOwn(commonParams, name) && commonParams[name] !== undefined) {
                    tempURL.searchParams.append(name, commonParams[name]);
                }
            }
        }
    }

    if (options.method == REQUEST_GET && window.ParamsIntegration) {
        return window.ParamsIntegration.toIntegrationFormData(getURL());
    }

    return {
        url: getURL()
    };
};

/**
 * 整合请求数据
 * @returns {string|FormData}
 */
const makeData = (options, config) => {
    let data = options.data;
    let headers = options.headers;

    if (options.method != REQUEST_GET) {
        if (config.onGetRequestCommonFields) {
            const commonParams = config.onGetRequestCommonFields(options.url, config);

            if (typeof commonParams == 'object') {
                Object.assign(data, commonParams);
            }
        }
    }

    if (options.method == REQUEST_ROW) {
        options.method = REQUEST_POST;
        headers['Content-Type'] = 'text/plain;charset=UTF-8';
        
        if (window.ParamsIntegration) {
            data = window.ParamsIntegration.toIntegrationObject(data);
        }

        data = JSON.stringify(data);
    } else if (options.method == REQUEST_POST) {
        delete headers['Content-Type'];
        const formData = new FormData();

        for (const key in data) {
            if (hasOwn(data, key)) {
                formData.append(key, data[key]);
            }
        }

        data = formData;

        if (window.ParamsIntegration) {
            data = window.ParamsIntegration.toIntegrationFormData(data);
        }
    } else if (!hasOwn(headers, 'Content-Type')) {
        data = qs.stringify(data);
        headers['Content-Type'] = 'application/x-www-form-urlencoded';

        if (window.ParamsIntegration) {
            data = window.ParamsIntegration.toIntegrationURLSearch(data);
        }
    }

    return {
        data,
        headers
    };
};

/**
 * [核心] 主要请求方法
 * @param {*} options 请求方配置
 * @param {*} config 可选，公共方及自定义配置
 * @returns {Promise<any>}
 */
export const request = (options, config) => {
    const requestOptions = {
        url    : '',
        method : 'POST',
        params : {},
        headers: {},
        data   : {},
        toBlank: false, // 是否跳转到空白页
        ...options
    };

    const requestConfig = {
        ...getHttp('http'),
        ...config,
    };

    // 选择模型返回调用
    return requestModel(getHttpInfo('model'), requestOptions, requestConfig);
}

/**
 * 选择请求模型后调用
 * @param {'ajax'|'fetch'|'axios'} model 默认ajax，外部配置
 * @param {*} options 
 * @param {*} config 
 * @returns {Promise<any>}
 */
export const requestModel = (model, options, config) => {
    options.method = options.method.toUpperCase();
    const { url } = makeUrl(options, config);
    const { data, headers } = makeData(options, config);

    options.url = url;
    options.data = data;
    options.headers = headers;

    return new Promise((resolve, reject) => {
        if (options.toBlank) {
            resolve(createBlankForm(options).then(({ run }) => {
                return run();
            }));
            return;
        }

        import(`./model/${model}`)
            .then(({ request }) => {
                return request(options, config);
            })
            .then((result) => {
                resolve(result);
            })
            .catch((error) => {
                reject(error);
            });
    });
};
